package cn.aitrox.ry.app.web.controller.auth;

import cn.aitrox.ry.app.web.vo.auth.group.in.AuthGroupCreateInVo;
import cn.aitrox.ry.app.web.vo.auth.group.in.AuthGroupUpdateInVo;
import cn.aitrox.ry.app.web.vo.auth.group.out.AuthGroupAllOutVo;
import cn.aitrox.ry.app.web.vo.auth.group.out.AuthGroupCreateOutVo;
import cn.aitrox.ry.app.web.vo.auth.group.out.AuthGroupDetailOutVo;
import cn.aitrox.ry.app.web.vo.auth.role.out.AuthRoleDetailOutVo;
import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.common.service.api.dto.User;
import cn.aitrox.ry.service.auth.dto.group.in.AuthGroupCreateInDto;
import cn.aitrox.ry.service.auth.dto.group.in.AuthGroupUpdateInDto;
import cn.aitrox.ry.service.auth.dto.group.out.AuthGroupDetailDto;
import cn.aitrox.ry.service.auth.dto.role.out.AuthRoleDetailDto;
import cn.aitrox.ry.service.auth.feign.AuthGroupFeign;
import cn.aitrox.ry.service.user.dto.in.UserListInDto;
import cn.aitrox.ry.service.user.feign.UserFeign;
import cn.aitrox.ry.util.ArrayUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

@RestController
public class AuthGroupController {

    @Autowired
    @Lazy
    private AuthGroupFeign authGroupFeign;

    @Autowired
    @Lazy
    private UserFeign userFeign;

    @PostMapping(value = "/auth/group")
    RespResult<AuthGroupCreateOutVo> create(@Validated @RequestBody AuthGroupCreateInVo input) {
        RespResult<Integer> respResult = authGroupFeign.create(new AuthGroupCreateInDto(input.getName(), input.getUserIds(), input.getRoleIds()));
        if (!respResult._isOk()) {
            return RespResult.secByError(respResult.getCode(), respResult.getMsg());
        }
        return RespResult.ok(new AuthGroupCreateOutVo(respResult.getData()));
    }

    @PutMapping(value = "/auth/group")
    RespResult update(@Validated @RequestBody AuthGroupUpdateInVo input) {
        return authGroupFeign.update(new AuthGroupUpdateInDto(input.getId(), input.getName(), input.getUserIds(), input.getRoleIds()));
    }

    @GetMapping(value = "/auth/group{id}")
    RespResult<AuthGroupDetailOutVo> read(@PathVariable("id") Integer id) {
        RespResult<AuthGroupDetailDto> respResult = authGroupFeign.read(id);
        if (!respResult._isOk()) {
            return RespResult.secByError(respResult.getCode(), respResult.getMsg());
        }

        AuthGroupDetailDto groupDetail = respResult.getData();
        List<Integer> userIds = groupDetail.getUserIds();
        List<AuthRoleDetailDto> roles = groupDetail.getRoles();

        List<User> users = null;
        List<AuthRoleDetailOutVo> rolesOutVo = null;

        if (!ArrayUtil.isEmpty(userIds)) {
            users = userFeign.list(new UserListInDto(userIds));
        }
        if (!ArrayUtil.isEmpty(roles)) {
            rolesOutVo = roles.stream().map(x -> new AuthRoleDetailOutVo(x.getId(), x.getName(), null, null, null)).collect(Collectors.toList());
        }

        return RespResult.ok(new AuthGroupDetailOutVo(groupDetail.getId(), groupDetail.getName(), groupDetail.getCreateTime(), groupDetail.getUpdateTime(), users, rolesOutVo));
    }

    @DeleteMapping(value = "/auth/group/{id}")
    RespResult delete(@PathVariable("id") Integer id) {
        return authGroupFeign.delete(id);
    }

    @GetMapping(value = "/auth/group/all")
    public RespResult<AuthGroupAllOutVo> all() {
        List<AuthGroupDetailDto> all = authGroupFeign.all();
        if (ArrayUtil.isEmpty(all)) {
            return RespResult.ok(new AuthGroupAllOutVo());
        }

        List<Integer> allUserId = all.stream().filter(x -> !ArrayUtil.isEmpty(x.getUserIds())).map(AuthGroupDetailDto::getUserIds).flatMap(Collection::stream).collect(Collectors.toList());
        allUserId = allUserId.stream().distinct().collect(Collectors.toList());

        List<User> allUser = new ArrayList<>();
        if (!ArrayUtil.isEmpty(allUserId)) {
            allUser = userFeign.list(new UserListInDto(allUserId));
        }

        final List<User> allUserFinal = allUser;

        return RespResult.ok(new AuthGroupAllOutVo(all.stream().map(x -> {
            List<User> usersByGroupId = null;
            List<AuthRoleDetailOutVo> rolesOutVo = null;

            if (!ArrayUtil.isEmpty(x.getUserIds())) {
                usersByGroupId = allUserFinal.stream().filter(user -> x.getUserIds().contains(user.getId())).collect(Collectors.toList());
            }

            if (!ArrayUtil.isEmpty(x.getRoles())) {
                rolesOutVo = x.getRoles().stream().map(y -> new AuthRoleDetailOutVo(y.getId(), y.getName(), null, null, null)).collect(Collectors.toList());
            }
            return new AuthGroupDetailOutVo(x.getId(), x.getName(), x.getCreateTime(), x.getUpdateTime(), usersByGroupId, rolesOutVo);
        }).collect(Collectors.toList())));
    }
}
